/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.mzk.oai.metadataRepository.cli;

import cz.mzk.kramerius.commons.Dom4jUtils;
import cz.mzk.oai.metadataRepository.repository.Repository;
import cz.mzk.oai.metadataRepository.sysnoSignatureMapping.Mapping;
import cz.mzk.oai.metadataRepository.sysnoSignatureMapping.XmlMappingsLoader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;

/**
 *
 * @author Martin Řehánek (rehan at mzk.cz)
 */
public class Main {

    private static final String ALL_COLLECTIONS = CollectionParser.ALL_COLLECTIONS;
    private static final Logger logger = Logger.getLogger(Main.class.getName());
    private static Repository repository;
    static Properties properties;
    static String usage = "Usage: java -jar repositoryManager.jar properties_file \n"
            + "harvest_aleph from to alephBase|\n"
            + "harvest_aleph_new days_ago alephBase|\n"
            + "harvest_aleph_all alephBase|\n"
            + "harvest_tei_new days_ago\n"
            + "harvest_tei_latest\n"
            + "move_items file_with_id_list"
            + "print_collections|print_sets|\n"
            + "print_collections_of_items items_id_list\n"
            + "print_possible_moves collectionName alephBase\n"
            + "scan_and_move collectionName alephBase\n"
            + "auto_transformations marc21|tei collection name| " + ALL_COLLECTIONS + "\n"
            //+ "analyze marc21 datafield856|subfield040b collection_name|" + ALL_COLLECTIONS + " |ese dc_language|europeana_isShownBy|europeana_isShownAt|europeana_object collection_name|" + ALL_COLLECTIONS + " \n"
            + "validate marc21|ese|oai_dc| collection_name|" + ALL_COLLECTIONS + " \n"
            + "save_mapping maping_file collection1 collection2 ...\n";

    public static void main(String[] args) {
        //set to true to bypass cli when testing new stuff
        boolean test = false;
        if (test) {
            methodForTestingNewFeatures();
            return;
        }

        //String myPropertiesFile = "C:\\Users\\Martin\\Documents\\NetBeansProjects\\repositoryManager\\laptop.properties";
        String myPropertiesFile = "/home/rehan/NetBeansProjects/MoZaKi/src/main/resources/provider-work.properties";
        //String myPropertiesFile = "production.properties";


        String[] testArgs = new String[]{myPropertiesFile,
            //"move_items", "/home/rehan/rukopisy/moveItems/manuscriptsBefore18002rkp_Moll_before1800_struct.txt"
            //"auto_transformations","marc21", "schramPortraitsBefore1800"
            //"auto_transformations","marc21", "schramVeduteBefore1800"
            //"harvest_tei_latest"
            //"auto_transformations","marc21" , "schramPortraitsAfter1800"
            //"auto_transformations", "tei_p5", "rkp_Moll_before1800_struct"
            //"print_collections_of_items",  "/home/rehan/oai/atlasy/ids.txt"
            //"harvest_aleph_all"
            //"harvest_aleph_new", "2", "MZK03"
            //"print_collections_of_items",  "/home/rehan/Stažené/vhodne_pro_EOD.mzk03.test"
            //"print_collections"
            "print_possible_moves", "generalMzk01After1800", "MZK01"
        };
        //args[1] = "harvest_tei";
        //args[1] = "print_collections";
//        args[1] = "harvest_aleph_new";
        //args[2] = "/home/rehan/rukopisy/mapping.xml";
        //args[2] = "/home/tomcat/oai/dist2/mapping.xml";
        //args = testArgs;
        try {
            checkArgs(args);
            loadProperties(args[0]);
            repository = Repository.instanceOf(properties);
            //repository = null;
            List<String> parameters = extractParameters(args);
            Action action = determineAction(args[1], parameters);
            action.run();
        } catch (Throwable e) {
            logger.log(Level.SEVERE, null, e);
            System.err.println(usage);
        }
    }

    private static void methodForTestingNewFeatures() {
//        File mappingFile = new File("/home/rehan/rukopisy/mapping.xml");
//        XmlMappingsLoader loader = new XmlMappingsLoader(mappingFile);
//        List<Mapping> mappings = loader.loadMappings();
//        System.err.println("mappings: " + mappings.size());

        try {
            Document doc = Dom4jUtils.loadDocument(new File("/home/rehan/NetBeansProjects/TestProjectMvn/src/main/resources/marc21test2.xml"), false);
            System.err.println("doc loaded");
            //Document xslt = Dom4jUtils.loadDocument(new File("/home/rehan/NetBeansProjects/RepositoryManagerMvn/src/main/resources/cz/mzk/oai/xslt/marc2ese-mzk01.xsl"), false);
            //Document xslt = Dom4jUtils.loadDocument(new File("/home/rehan/NetBeansProjects/TestProjectMvn/src/main/resources/MARC21slimUtils.xsl.xml"), false);
            Document xslt = Dom4jUtils.loadDocument(new File("/home/rehan/NetBeansProjects/RepositoryManagerMvn/src/main/resources/cz/mzk/oai/xslt/marc2dc.xsl"), false);
            System.err.println("xslt loaded");
            Document transformed = Dom4jUtils.transformDocument(doc, xslt);
            System.out.println(transformed.asXML());
        } catch (Exception ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    private static void checkArgs(String[] args) throws Exception {
        if (args.length < 2) {
            throw new Exception("At least 2 arguments needed. Only " + args.length + " arguments were presented");
        }
    }

    private static void loadProperties(String propertiesFile) throws IOException {
        InputStreamReader reader = new FileReader(propertiesFile);
        properties = new Properties();
        properties.load(reader);
    }

    private static List<String> extractParameters(String[] args) {
        int parametersStartAtIndex = 2;
        List<String> result = new ArrayList<String>(args.length - parametersStartAtIndex);
        for (int i = parametersStartAtIndex; i < args.length; i++) {
            result.add(args[i]);
        }
        return result;
    }

    private static Action determineAction(String verb, List<String> parameters) throws Exception {
        if ("harvest_aleph".equals(verb)) {
            checkNumberOfParametersForAction(parameters, 3, "harvest_aleph");
            return new HarvestMarcFromUntilAction(repository, properties, parameters.get(0), parameters.get(1), parameters.get(2));
        }
        if ("harvest_aleph_new".equals(verb)) {
            checkNumberOfParametersForAction(parameters, 2, "harvest_aleph_new");
            return new HarvestMarcNewAction(repository, properties, parameters.get(0), parameters.get(1));
        }
        if ("harvest_aleph_all".equals(verb)) {
            checkNumberOfParametersForAction(parameters, 1, "harvest_aleph_all");
            return new HarvestMarcAllAction(repository, properties, parameters.get(0));
        }
        if ("harvest_tei_new".equals(verb)) {
            checkNumberOfParametersForAction(parameters, 1, "harvest_tei_new");
            return new HarvestTeiNewAction(repository, properties, parameters.get(0));
        }
        if ("harvest_tei_latest".equals(verb)) {
            return new HarvestTeiFromLatestRevisionAction(repository, properties);
        }
        if ("move_items".equals(verb)) {
            checkNumberOfParametersForAction(parameters, 1, "move_items");
            return new MoveItemsAction(repository, parameters.get(0));
        }
        if ("print_collections".equals(verb)) {
            return new PrintCollectionsAction(repository);
        }
        if ("print_collections_of_items".equals(verb)) {
            checkNumberOfParametersForAction(parameters, 1, "print_collections_of_items");
            return new PrintCollectionsOfItemsAction(repository, parameters.get(0));
        }
        if ("print_possible_moves".equals(verb)) {
            checkNumberOfParametersForAction(parameters, 2, "print_possible_moves");
            return new PrintPossibleMovesAction(repository, parameters.get(0), parameters.get(1));
        }
        if ("scan_and_move".equals(verb)) {
            checkNumberOfParametersForAction(parameters, 2, "scan_and_move");
            return new ScanCollectionAction(repository, parameters.get(0), parameters.get(1));
        }
        if ("print_sets".equals(verb)) {
            return new PrintSetsAction(repository);
        }
        if ("auto_transformations".equals(verb)) {
            checkNumberOfParametersForAction(parameters, 2, "auto_transforms");
            return new AutomaticTransformationsAction(repository, parameters.get(0), parameters.get(1));
        }
        if ("validate".equals(verb)) {
            checkNumberOfParametersForAction(parameters, 2, "validate");
            return new ValidateMetadataAction(repository, parameters.get(0), parameters.get(1), true);
        }
        if ("save_mapping".equals(verb)) {
            if (parameters.size() <= 1) {
                throw new Exception("At least two parameters required - file for storing mapping and at least one collection");
            }
            return new SaveMappingAction(repository, parameters);
        }
        throw new IllegalArgumentException("No such action '" + verb + "'");
    }

    private static void checkNumberOfParametersForAction(List<String> parameters, int requiredSize, String actionName) throws Exception {
        if (parameters.size() != requiredSize) {
            throw new Exception("Illegal number of parameters (" + parameters.size() + ") for action " + actionName);
        }
    }
}
